package com.cctc.juc.source.Athread;

import sun.nio.ch.Interruptible;
import sun.security.util.SecurityConstants;

import java.security.AccessControlContext;

/**
 * Thread 类
 * - 核心知识点 [源码解析]。
 * [数据结构]：
 * - 进程：进程是操作系统资源分配的基本单位。一个进程由程序段、数据段和进程控制块（PCB [pid、name、 status、priority、context、startAddress、fd 等等]）组成。
 * - 线程：线程是 CPU 调度执行的基本单位。一个标准的线程主要由三部分组成，线程基本信息（tid、name、status、group、priority、deamon、target 等等）、程序计数器（PC）和栈（方法帧）内存。
 * [进程和线程的关系]
 * - 线程是基于高并发调度诉求从进程内部演化而来的，又称为 “轻量级进程”，是进程 “程序段” 的一次顺序执行。
 * - 一个进程可以有一个或多个线程，各个线程之间共享进程的内存空间（方法区内存、堆内存）、系统资源（文件句柄、系统信号）等。
 * - 线程的出现既弥补了进程调度过于笨重的问题，同时又充分发挥了 CPU 的性能。
 * [线程和协程的关系]
 * - 协程：“协作的线程” 或 “协作的函数”，是一种用户级的 “轻量级线程”，共享线程的栈内存空间，一个线程中可以运行成千上万个协程，这些协程由用户进行调度，不需要切换到内核态，编程模型简单，只需要通过挂起和恢复操作就可以实现多任务并发执行，避免了复杂的线程同步问题。
 * 支持协程技术的编程语言包括：
 * - Go 语言，Go 语言内置的 goroutine 是对协程的实现，它提供了轻量级的并发处理能力，非常适合构建高性能的分布式系统和微服务架构；
 * - Kotlin 语言，Kotlin 是一种运行在 JVM 上的静态类型编程语言，它提供了对协程的原生支持，通过 kotlin.coroutine 库，可以轻松使用协程来编写并发代码；
 * - Lua 脚本语言：Lua 是一种轻量级的脚本语言，可以运行在 Nginx、Redis 等组件内，Lua 中的 coroutine 库提供了创建和管理协程的功能，可以实现在单个线程内调度多个任务的并发执行。
 * - 其他如 C++、C#、JS、Python、PHP、Ruby 等也都提供了协程的实现。
 * 面试题：
 * 1. 如果获取 JVM 进程的线程堆栈（-Xss）信息？
 * JVM 进程的线程堆栈（-Xss）信息指的是 JVM 中活动线程（JVM 线程、用户线程正在执行的方法堆栈信息）列表，它对于分析系统瓶颈和死锁问题非常有用。
 * 方法一：首先使用 jps 查看 JVM 进程号（PID），然后使用 jstack pid 查看线程堆栈信息，包括当前 JVM 实例内所有线程（JVM 线程、用户线程）正在执行的方法堆栈信息。
 * - jstack 工具是 JDK 自带的基于终端交互的工具，使用简单，可以基于脚本进行定时或条件触发等方式生成线程堆栈转储快照进行分析。
 * 方法二：对于 Windows 系统，使用 Ctrl + Break 组合键、对于 Linux 系统，使用 kill - 3 命令生成当前 JVM 实例内所有线程（JVM 线程、用户线程）正在执行的方法堆栈转储快照文件。
 * 方法三：使用 Profiler 等 JVM 监控工具。
 */
public class AThread_AAAAA implements BRunnable {

    // --- [核心] 属性 --- //

    private long tid;
    private volatile String name;
    // 线程状态
    private volatile int threadStatus = 0;
    // 线程 [同步控制] 持有的（内部）互斥锁
    private final Object blockerLock = new Object();
    // 线程（阻塞 | 等待）中断接口，用于释放持有的（内部）互斥锁，避免死锁（互斥、[破坏] 不可剥夺、请求与保持、循环等待）
    private volatile Interruptible blocker;

    public enum State {
        /**
         * [线程生命周期] 线程运行状态变化过程。
         * 1. 主流程：线程创建 -> 启动（CPU 调度执行） -> 终止 [NEW -> RUNNBALE -> TERMANITED]；
         * 2. 线程同步流程：线程阻塞（抢锁失败 -> 自我阻塞 -> 被动唤醒）[NEW -> RUNNABLE -> BLOCKED -> RUNNABLE -> TERMANITED]；
         * 3. 线程通信流程：线程等待（限时等待 -> 自我唤醒；条件等待 -> 被动唤醒）[NEW -> RUNNBALE -> {TIMED_}WAITING -> RUNNBALE -> TERMANITED]
         * 4. 线程中断流程：线程中断（线程 {运行 | 阻塞 | 等待} -> {主动 | 被动} 中断 -> {主动检测 | 异常捕获} 唤醒）[NEW -> RUNNBALE | BLOCKED | {TIMED_}WAITING -> RUNNABLE -> TERMINATED]
         */
        NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMANITED;
    }

    private ThreadGroup group;
    private int priority;
    public static final int MIN_PRIORITY = 1, NORM_PRIORITY = 5, MAX_PRIORITY = 10;
    private boolean deamon = false;
    // 目标任务
    private Runnable target;
    // 线程 [类加载器]
    private ClassLoader contextClassLoader;
    // 线程本地变量，由 ThreadLocal 类进行维护
    ThreadLocal.ThreadLocalMap threadLocals = null;
    // [{父线程 -> 子线程} 可继承的] 线程本地变量，由 InheritableThreadLocal 类进行维护
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    // 线程 [栈内存容量]，使用 {-Xss: 1m} 显式配置，默认由 JVM 配置为 {-Xss: 256k}
    private long stackSize;

    // --- [常用] 构造器 --- //

    public AThread_AAAAA(Runnable target) {
        // 线程创建 [初始化]
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    public AThread_AAAAA(Runnable target, String name) {
        // 线程创建 [初始化]
        init(null, target, name, 0);
    }

    public AThread_AAAAA(ThreadGroup group, Runnable target, String name) {
        // 线程创建 [初始化]
        init(group, target, name, 0);
    }

    // --- [核心] 方法 --- //

    private void init(ThreadGroup g,
                      Runnable target,
                      String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }

    /**
     * 创建 -> 初始化线程 [NEW]
     */
    private void init(ThreadGroup g,
                      Runnable target,
                      String name,
                      long stackSize,
                      AccessControlContext acc,
                      boolean inheritThreadLocals) {
        this.tid = nextThreadID();
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        this.name = name;
        /**
         * 说明：Thread 类中的构造器是由其所在的 [父线程] 调用的。
         * - 初始化时，新创建的 [子线程] 会继承 [父线程] 的部分属性。
         */
        Thread parent = currentThread();
        // 省略部分代码 ...
        this.group = g;
        this.priority = parent.getPriority();
        setPriority(priority);
        this.daemon = parent.isDaemon();
        // 省略部分代码 ...
        this.target = target;
        // [{父线程 -> 子线程} 可继承的] 线程局部变量，自动继承 [父线程] 的 inheritableThreadLocals 变量。
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        this.stackSize = stackSize;
    }

    /**
     * 启动线程 [NEW -> RUNNABLE]
     * - 线程启动为互斥操作，使用 synchronized 进行同步控制。
     * 所以，一个线程只能启动一次，多次启动将会抛出异常。
     * [面试题] 为什么线程只能启动一次？多次启动为什么会抛出异常？
     * 参考答案：线程启动后，将变为 [NEW -> RUNNABLE] 就绪状态，等待 CPU 自动调度执行。该状态不再受 Java 的控制，无法重置，因此只能启动一次；该方法将会在启动前检查线程的状态，如果不为 NEW，则直接抛出异常。
     */
    public synchronized void start() {
        if (threadStatus != 0) throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            // [启动线程] 具体实现，为本地方法，线程状态变为 [NEW -> RUNNABLE] 后由 CPU 进行调度，调用 run() 方法，执行目标任务。
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }

    private native void start0();

    /**
     * 运行线程 [NEW -> RUNNABLE -> CPU 执行目标任务 -> TERMINATED]
     * - 执行目标任务 target.run()。
     */
    @Override
    public void run() {
        if (target != null) {
            // 执行目标任务
            target.run();
        }
    }

    /**
     * 获取当前运行线程 [NEW -> RUNNABLE -> CPU 执行目标任务]
     * - 获取当前 CPU 内核上正在运行的线程实例。
     * 说明：虽然一个进程可以有很多个线程，但是在一个 CPU 内核上，同一时刻只能有一个线程被执行，该线程也被叫做 [当前线程]。
     */
    public static native Thread currentThread();

    /**
     * 当前线程 “让出（CPU 时间片）”。
     * - 老版本使用的是 Thread.yeild() 方法；
     * - 新版本使用的是 Thread.sleep(0) 方法。
     * 说明：二者都是希望 “让出” CPU 资源，让其他线程有竞争 CPU 资源的机会，线程状态由 RUNNING 变为 RUNNABLE，但是：
     * - yield() 方法只是给 CPU 提醒该线程愿意暂时释放 CPU 资源，如果 CPU 资源不紧张，会忽略掉这个提醒，且 yield() 方法在执行期间无法捕获中断异常；
     * - sleep() 方法的作用本身就是让该线程进入休眠状态，让出 CPU 资源，所以 Thread.sleep(0) 一定会 “触发操作系统立刻重新进行一次 CPU 竞争”，让其他线程有竞争 CPU 资源的机会，且 sleep() 方法在执行期间可以捕获到中断异常。
     */
    public static native void yield();

    /**
     * {当前线程} 自我休眠 [NEW -> RUNNABLE -> TIMED_WAITING]
     * - 自我等待一段时间后自动唤醒。
     * LockSupport.park() 与 Thread.sleep() 方法类似，都可以让当前线程休眠。
     * 二者的区别：
     * 1. Thread.sleep() 方法只能自己醒过来（不会释放持有的互斥锁，除非 {手动 | 被动} 触发中断异常）；而被 LockSupport 可以调用 LockSupport.unpark() 方法手动唤醒（释放持有的互斥锁）。即 LockSupport 可以更加精准、灵活的休眠、唤醒指定的线程，且 LockSupport 还允许设置一个 Blocker 对象，用来查看线程等待的原因。
     * 2. Thread.sleep() 方法抛出了中断异常，调用者必需要 [显式] 捕获或者再抛出；而 LockSupport.park() 不会抛出异常（仅设置了线程的中断标志），调用时不必需要 [显式] 捕获中断异常或者再抛出（当然，也可以根据需要主动判断是否出现了中断异常并处理）。
     */
    public static native void sleep(long millis) throws InterruptedException;

    /**
     * {当前线程} 不限时条件等待 [NEW -> RUNNBALE -> WAITING]
     * - 当前线程 cur 调用 Target 线程的 join() 方法，进行自我阻塞，直到 Target 线程执行结束后被唤醒，再继续向下执行。
     * 底层是基于 Object 对象监视器（重量级锁）的等待与唤醒机制进行实现的。
     */
    public final void join() throws InterruptedException {
        join(0);
    }

    public final synchronized void join(long millis)
            throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (millis == 0) {
            while (isAlive()) {
                // Object.wait() 本地方法，让 {父线程} 等待，直到 {子线程} 超时或终止。
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

    /**
     * {手动} 中断线程 [NEW -> {RUNNBALE | WAITING | TIMED_WAITING | BLOCKED } -> RUNNABLE]
     * 1. 设置中断标志（软中断）
     * 2. 触发中断动作
     * 说明：这种中断线程的方式比较安全，它使得正在执行的任务正常执行（可以 [主动检测] 中断标志（软中断）或 [捕获中断异常] 并执行中断处理逻辑），而不像 stop() 方法那样强制杀死线程，产生死锁风险。
     */
    public staic void interrupt() {
        if (this != AThread_AAAAA.currentThread())
            checkAccess();
        // 同步控制
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                // 设置中断标志（软中断）
                interrupt0();
                // 触发中断动作
                b.interrupt(this);
                return;
            }
        }
        // 如果失败，设置中断标志（软中断）
        interrupt0();
    }

    private native void interrupt0();

    /**
     * 面试题：Thread.interrupted() 和 t.isInterrupted() 方法的区别？？？
     * 提示：考察 Java 多线程中断机制。
     * 参考答案：Java 多线程的中断机制是使用内部中断标识来实现的。
     * 1. 应用程序调用 Thread.interrupt() 方法来中断一个线程，设置中断标识为 true。
     * 2. 中断线程调用 Thread.interrupted() 静态方法来检测自我中断状态时，中断标识会被清除；
     * 3. 其他线程调用 t.isInterrupted() 非静态方法来查询指定线程的中断状态时不会改变目标线程的中断标识。
     */
    public static boolean interrupted() {
        return isInterrupted(true);
    }

    public boolean isInterrupted() {
        return isInterrupted(false);
    }

    /**
     * 判断线程是否设置了中断标志（软中断）？
     *
     * @param ClearInterrupted 是否清除中断标志（软中断）？
     * @return 结果
     */
    protected native static boolean isInterrupted(boolean ClearInterrupted);

    /**
     * （过时，禁用）终止线程 [NEW -> {RUNNABLE | TIMED_WAITING | WAITING | BLOCKED} -> TERMINATED]
     * - 强制杀死线程，立即结束执行。
     * 注意：该方法已经标记为 {过时}，不再建议使用（推荐使用 Thread.interrupt() 方法或通过 {设置状态位} 来控制线程正常终止）。因为该方法会立即杀死线程，如果当前线程持有互斥锁，则无法释放，从而导致死锁（互斥、不可剥夺、请求与保持、循环等待）。
     * - 类似的方法还有 suspend()、resume()、destory() 等，会产生同样的问题，不再建议使用。
     * 面试题：Java 中如何停止一个线程？
     * JDK 1.0 本来提供了像 stop()、suspend()、resume()、destory() 等停止、挂起、销毁线程的方法，但是由于其会导致存在潜在的死锁问题而在后续的版主本中被全部被弃用了。
     * 到目前为止，Java 中还没有提供一种以线程安全的方式停止线程的方法。
     * 对于一个线程来说，当它执行完 run() 之后，就会自动终止。
     * 如果要手动终止一个线程，可以使用中断标识volatile 状态变量或来控制 run() 方法结束执行，从而终止线程。
     */
    @Deprecated
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if (this != AThread_AAAAA.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        // A zero status value corresponds to "NEW", it can't change to
        // not-NEW because we hold the lock.
        if (threadStatus != 0) {
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }

        // 本地方法，强制杀死线程，立即结束执行。
        stop0(new ThreadDeath());
    }

    private native void stop0(Object o);

}
